package be.ipl.diavoloz.modele;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MapKeyJoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.swing.JComboBox;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.NotBlank;

@Entity
@Table(schema = "DIAVOLOZ", name = "PARTIE")
public class Partie implements Serializable {

	private static final long serialVersionUID = 528709854512096419L;

	public enum Etat {

		ATTENTE_JOUEURS {
			@Override
			public boolean ajouterJoueur(Partie partie, Joueur joueur) {
				partie.mesPoints.put(joueur, 5);
				return true;
			}

			@Override
			public boolean commencerPartie(Partie partie) {
				partie.etat = EN_COURS;
				partie.nombreJoueursPouvantJouer = partie.getNombreJoueurs();
				return true;
			}

			@Override
			public boolean supprimerJoueur(Partie partie, Joueur joueur) {
				partie.mesPoints.remove(joueur);
				return true;
			}
		},
		EN_COURS {

			@Override
			public boolean supprimerJoueur(Partie partie, Joueur joueur) {
				partie.mesPoints.remove(joueur);
				return true;
			}

			@Override
			public boolean terminerPartie(Partie partie) {
				partie.etat = Etat.TERMINEE;
				return true;
			}

			@Override
			public Tour ajouterUnTour(Partie partie, Tour tour) {
				partie.journal.add(tour);
				return tour;
			}
			
			@Override
			public Tour getTourCourant(Partie partie) {
				if(partie.journal.size() == 0) return null;
				Tour aRenvoyer = partie.journal.get(partie.journal.size()-1);
				if(aRenvoyer.getStatut().compareTo("terminer") == 0) return null;
				return aRenvoyer;
			}
			@Override
			public boolean enleverBouleDeCristal(Joueur joueur, Partie partie) {
				int pointActuel = partie.mesPoints.get(joueur);
				if(pointActuel <= 0) return false;
				pointActuel -= 1;
				partie.mesPoints.put(joueur, pointActuel);
				if(pointActuel == 0) partie.nombreJoueursPouvantJouer--;
				return true;
			}
			@Override
			public boolean ajouterBouleDeCristal(Joueur joueur, Partie partie) {
					int pointActuel = partie.mesPoints.get(joueur);
					if(pointActuel >= 5) return false;
					partie.mesPoints.put(joueur, pointActuel++);
					return true;
			}

		},TERMINEE() {
			@Override
			public Joueur getVainqueur(Partie partie) {
				Joueur gagnant = null;
				int pointMax = -1;
				Map<Joueur, Integer> map = partie.getMesPoints();
				for (Joueur j : map.keySet()) {
					
					
					if (map.get(j) > pointMax) {
						gagnant = j;
						pointMax = map.get(j);
					}		
				}
				if(pointMax == 0) return null;
				return gagnant;
			}
		};
		

		public boolean ajouterJoueur(Partie partie, Joueur joueur) {
			return false;
		}

		public Tour getTourCourant(Partie partie) {
			// TODO Auto-generated method stub
			return null;
		}

		public boolean ajouterBouleDeCristal(Joueur joueur, Partie partie) {
			// TODO Auto-generated method stub
			return false;
		}

		public boolean enleverBouleDeCristal(Joueur joueur, Partie partie) {
			// TODO Auto-generated method stub
			return false;
		}

		public Joueur getVainqueur(Partie partie) {
			return null;
		}

		public Tour ajouterUnTour(Partie partie, Tour tour) {
			return null;
		}

		public boolean terminerPartie(Partie partie) {
			return false;
		}

		public boolean supprimerJoueur(Partie partie, Joueur joueur) {
			return false;
		}

		public boolean commencerPartie(Partie partie) {
			return false;
		}

	};

	@Enumerated
	private Etat etat = Etat.ATTENTE_JOUEURS;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@NotNull
	@NotBlank
	private String nom;

	@OneToMany
	private List<Tour> journal;

	@ElementCollection
	@CollectionTable(schema = "DIAVOLOZ", name = "JOUEURS_PARTIES")
	@Column(name = "POINTS")
	@MapKeyJoinColumn(name = "JOUEUR_ID")
	private Map<Joueur, Integer> mesPoints = new HashMap<Joueur, Integer>();

	@Max(6)
	private int nombreJoueursPouvantJouer;

	@Column
	private Calendar dateDebut;


	protected Partie() {
	}

	public Partie(String nom) {
		this.nom = nom;
		this.dateDebut = new GregorianCalendar();
		this.nombreJoueursPouvantJouer = 0;
	}

	public String getNom() {
		return this.nom;
	}

	public Calendar getDateDebut() {
		return this.dateDebut;
	}

	public Etat getEtat() {
		return etat;
	}

	public List<Tour> getJournal() {
		return journal;
	}

	public Integer getId() {
		return this.id;
	}

	public List<Joueur> getListeJoueurs() {
		List<Joueur> liste = new ArrayList<Joueur>();
		for (Joueur j : mesPoints.keySet()) {
			liste.add(j);
		}
		return liste;
	}

	public int getNombreJoueurs() {
		return this.mesPoints.size();
	}

	public Map<Joueur, Integer> getMesPoints() {
		return mesPoints;
	}

	public boolean ajouterJoueur(Joueur joueur) {
		return this.etat.ajouterJoueur(this, joueur);
	}

	public Joueur getVainqueur() {
		return this.etat.getVainqueur(this);
	}

	public Tour ajouterUnTour(Tour tour) {
		return this.etat.ajouterUnTour(this, tour);
	}

	public boolean terminerPartie() {
		return this.etat.terminerPartie(this);
	}

	public boolean supprimerJoueur(Joueur joueur) {
		return this.etat.supprimerJoueur(this, joueur);
	}

	public boolean commencerPartie() {
		return this.etat.commencerPartie(this);
	}
	
	public boolean ajouterBouleDeCristal(Joueur joueur) {
		return etat.ajouterBouleDeCristal(joueur, this);
	}

	public boolean enleverBouleDeCristal(Joueur joueur) {
		return etat.enleverBouleDeCristal(joueur, this);
	}
	
	public boolean peutJouer(Joueur joueur){
		if(mesPoints.get(joueur) == 0) return false;
		return true;
	}

	public int getNombreJoueursPouvantJouer() {
		return nombreJoueursPouvantJouer;
	}

	public void setEtat(Etat etat) {
		this.etat = etat;
	}

	public void setNombreJoueursPouvantJouer(int nombreJoueursPouvantJouer) {
		this.nombreJoueursPouvantJouer = nombreJoueursPouvantJouer;
	}
	
	
	public Tour getTourCourant() {
		return this.etat.getTourCourant(this);
	}

}
